package com.teamsun.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.teamsun.annotation.PrivateHandlerMethod;
import com.teamsun.cache.CacheManager;
import com.teamsun.entity.AccessIn;
import com.teamsun.entity.TableHeader;
import com.teamsun.exception.ServiceException;
import com.teamsun.rptcfg.BaseRpt;
import com.teamsun.rptcfg.BaseRptColumn;
import com.teamsun.rptcfg.ParseRptCfg;
import com.teamsun.service.IRptMgrService;
import com.teamsun.service.ISaveRptService;
import com.teamsun.util.Constants;
import com.teamsun.util.ReadExcelHeader;
import com.teamsun.util.RptCfgUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>修改报表配置Controller</p>
 */
@Controller
@RequestMapping("/rptTools/editRpt")
public class EditRptController {

    @Autowired
    private ISaveRptService saveRptService;

    @Autowired
    private IRptMgrService rptMgrService;

    @Autowired
    private CacheManager cacheManager;

    /**
     * 导入报表配置
     */
    @RequestMapping("/importRptCfg")
    @ResponseBody
    @PrivateHandlerMethod
    public JSONObject importRptCfg(HttpServletRequest request, @RequestParam("rptCfg") MultipartFile rptCfg) {
        JSONObject jsonObject = new JSONObject();
        try {
            // 获取文件后缀名
            String oriFileName = rptCfg.getOriginalFilename();
            // 文件后缀名，报表配置文件只能时xml文件
            String fileSuffix = oriFileName.substring(oriFileName.lastIndexOf(".") + 1);
            if("xml".equalsIgnoreCase(fileSuffix)) {
                jsonObject.put("status", "1");
            } else {
                jsonObject.put("status", "0");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 保存报表配置信息(修改报表表头)
     */
    @RequestMapping("/editRptHeader")
    @ResponseBody
    @PrivateHandlerMethod
    public JSONObject editRptCfg(@RequestParam("rptCfg") MultipartFile rptCfg,@RequestParam("rptHeader") MultipartFile rptHeader,
                                 HttpServletRequest request) {
        JSONObject jsonObject = new JSONObject();
        String errroMsg = "";
        try {
            // 根据报表ID查询报表信息
            String rptId = request.getParameter("rptId");  // 报表ID
            String rptName = request.getParameter("rptName");  // 报表名称
            String dbSource = request.getParameter("dbSource");  // 报表数据源
            String accessIn = request.getParameter("accessIn");  // 接入系统
            String editHeader = request.getParameter("editHeader");  // 是否修改表头
            String token = "";
            if(StringUtils.isNotBlank(accessIn)) {
                // 接入系统Token
                List<AccessIn> accessIns = rptMgrService.queryAccessInByCode(accessIn);
                if(!CollectionUtils.isEmpty(accessIns)) {
                    token = accessIns.get(0).getSysToken();
                }
            }

            String fileName = rptCfg.getOriginalFilename();
            int beginIdx = fileName.lastIndexOf("_") + 1;
            int endIdx = fileName.indexOf(".xml");
            String fileId = fileName.substring(beginIdx, endIdx);

            String rptFileName = "RPT_" + rptId + ".xml";
            if(!rptId.equals(fileId)) {
                jsonObject.put("status", "0");
                jsonObject.put("errorMsg", "文件错误,请上传报表ID为[" + rptId + "]的配置文件");
                return jsonObject;
            }
            BaseRpt baseRpt = saveRptService.queryRptCfgById(rptId);

            // 解析报表配置文件
            ParseRptCfg parseRptCfg = new ParseRptCfg();
            BaseRpt rptInfo = parseRptCfg.parseRptCfg(rptCfg.getInputStream(), rptFileName);
            rptInfo.setRptId(baseRpt.getRptId());
            rptInfo.setRptName(rptName);
            rptInfo.setDataSource(dbSource);
            rptInfo.setRptToken(token);
            rptInfo.setAccessSysCode(accessIn);

            // 如果修改表头
            String rptHeaderJson = request.getParameter("rptHeaderJson");  // 表头信息;

            // 重置表头信息(补充表头信息中field、align、width等字段的值)
            List<List<TableHeader>> tableHeaders = RptCfgUtils.resetRptHeader(rptHeaderJson, rptInfo);
            PropertyFilter filter = new PropertyFilter() {
                @Override
                public boolean apply(Object object, String name, Object value) {
                    if((name.equals("sortable") && "false".equals(String.valueOf(value))) || ((name.equals("hidden") && "false".equals(String.valueOf(value)))) || (name.equals("colspan") && "0".equals(String.valueOf(value))) || ((name.equals("rowspan") && "0".equals(String.valueOf(value)))) || ((name.equals("width") && "0".equals(String.valueOf(value))))) {
                        return false;
                    }
                    return true;
                }
            };
            rptHeaderJson = JSON.toJSONString(tableHeaders, filter);
            rptInfo.setRptHeader(rptHeaderJson);

            // 将报表配置文件上传至服务器
            // 保存报表表头文件
            //String rptConfigPath = request.getSession().getServletContext().getRealPath("/WEB-INF/rptConfig");
            String rptConfigPath = (String) cacheManager.getCacheValue(Constants.RPTCFGPATH);
            String rptHeaderFilePath = (String) cacheManager.getCacheValue(Constants.RPTHEADERPATH);

            // 获取Excel表头信息
            ReadExcelHeader readExcelHeader = new ReadExcelHeader();
            // 修改报表表头，则使用新上传的表头Excel文件
            InputStream excelInputStream = rptHeader.getInputStream();
            List<String> titleList = readExcelHeader.getXlsxExcelHeaderInfo(excelInputStream, tableHeaders.size());
            rptInfo.setExcelHeader(titleList);

            // 报表配置文件中name属性配置的值必须和Excel表头相同，为了防止用户修改name属性的值，在此再次验证name属性的值
            List<BaseRptColumn> rptCloumns = rptInfo.getRptColumns();
            for(BaseRptColumn rptColumn : rptCloumns) {
                String name = rptColumn.getName();
                if(!titleList.contains(name)) {
                    errroMsg = "xml文件中cloumn元素的name属性值【" + name + "】配置错误，该值无法和Excel表头对应";
                    throw new ServiceException(errroMsg);
                }
            }

            // 修改报表配置信息
            saveRptService.updateRptCfg(editHeader, rptInfo);

            // 将报表表头文件上传至服务器
            // 获取文件后缀名
            String oriRptHeader = rptHeader.getOriginalFilename();
            String fileSuffix = oriRptHeader.substring(oriRptHeader.lastIndexOf(".") + 1);

            // 保存文件
            String headerFileName = "RPT_" + rptId + "." + fileSuffix;
            File rptHeaderFile = new File(rptHeaderFilePath, headerFileName);
            if(!rptHeaderFile.exists()) {
                rptHeaderFile.mkdirs();
            }
            rptHeader.transferTo(rptHeaderFile);

            // 报表配置文件上传
            // 保存文件
            String cfgFileName = "RPT_" + rptId + ".xml";
            File rptCfgFile = new File(rptConfigPath, cfgFileName);
            if (!rptCfgFile.exists()) {
                rptCfgFile.mkdirs();
            }
            rptCfg.transferTo(rptCfgFile);

            // 缓存报表配置数据
            System.out.println("缓存数据...");
            cacheManager.addRptCache(String.valueOf(rptId), rptInfo);

            jsonObject.put("status", "1");
        } catch (ServiceException e) {
            errroMsg = e.getMessage();
            jsonObject.put("status", "0");
            jsonObject.put("errorMsg", errroMsg);
        } catch (Exception e) {
            errroMsg = "修改报表失败";
            jsonObject.put("status", "0");
            jsonObject.put("errorMsg", errroMsg);
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 保存报表配置信息(修改报表配置信息，不修改表头)
     */
    @RequestMapping("/editRptCfg")
    @ResponseBody
    @PrivateHandlerMethod
    public JSONObject editRptCfg(@RequestParam("rptCfg") MultipartFile rptCfg,HttpServletRequest request) {
        JSONObject jsonObject = new JSONObject();
        String errroMsg = "";
        try {
            // 根据报表ID查询报表信息
            String rptId = request.getParameter("rptId");  // 报表ID
            String rptName = request.getParameter("rptName");  // 报表名称
            String dbSource = request.getParameter("dbSource");  // 报表数据源
            String accessIn = request.getParameter("accessIn");  // 接入系统
            String editHeader = request.getParameter("editHeader");  // 是否修改表头
            String token = "";
            if(StringUtils.isNotBlank(accessIn)) {
                // 接入系统Token
                List<AccessIn> accessIns = rptMgrService.queryAccessInByCode(accessIn);
                if(!CollectionUtils.isEmpty(accessIns)) {
                    token = accessIns.get(0).getSysToken();
                }
            }

            String fileName = rptCfg.getOriginalFilename();
            int beginIdx = fileName.lastIndexOf("_") + 1;
            int endIdx = fileName.indexOf(".xml");
            String fileId = fileName.substring(beginIdx, endIdx);

            String rptFileName = "RPT_" + rptId + ".xml";
            if(!rptId.equals(fileId)) {
                jsonObject.put("status", "0");
                jsonObject.put("errorMsg", "文件错误,请上传报表ID为[" + rptId + "]的配置文件");
                return jsonObject;
            }
            BaseRpt baseRpt = saveRptService.queryRptCfgById(rptId);

            // 解析报表配置文件
            ParseRptCfg parseRptCfg = new ParseRptCfg();
            BaseRpt rptInfo = parseRptCfg.parseRptCfg(rptCfg.getInputStream(), rptFileName);
            rptInfo.setRptId(baseRpt.getRptId());
            rptInfo.setRptName(rptName);
            rptInfo.setDataSource(dbSource);
            rptInfo.setRptToken(token);
            rptInfo.setAccessSysCode(accessIn);

            // 如果修改表头
            String rptHeaderJson = baseRpt.getRptHeader();

            // 重置表头信息(补充表头信息中field、align、width等字段的值)
            List<List<TableHeader>> tableHeaders = RptCfgUtils.resetRptHeader(rptHeaderJson, rptInfo);
            PropertyFilter filter = new PropertyFilter() {
                @Override
                public boolean apply(Object object, String name, Object value) {
                    if((name.equals("sortable") && "false".equals(String.valueOf(value))) || ((name.equals("hidden") && "false".equals(String.valueOf(value)))) || (name.equals("colspan") && "0".equals(String.valueOf(value))) || ((name.equals("rowspan") && "0".equals(String.valueOf(value)))) || ((name.equals("width") && "0".equals(String.valueOf(value))))) {
                        return false;
                    }
                    return true;
                }
            };
            rptHeaderJson = JSON.toJSONString(tableHeaders, filter);
            rptInfo.setRptHeader(rptHeaderJson);

            // 将报表配置文件上传至服务器
            String rptConfigPath = (String) cacheManager.getCacheValue(Constants.RPTCFGPATH);
            String rptHeaderFilePath = (String) cacheManager.getCacheValue(Constants.RPTHEADERPATH);

            // 获取Excel表头信息
            ReadExcelHeader readExcelHeader = new ReadExcelHeader();
            // 不修改表头信息，使用已有的报表表头Excel文件
            String excelFileName = "RPT_" + rptId + ".xlsx";
            File rptHeaderFile = new File(rptHeaderFilePath + "/" + excelFileName);
            InputStream excelInputStream = new FileInputStream(rptHeaderFile);
            List<String> titleList = readExcelHeader.getXlsxExcelHeaderInfo(excelInputStream, tableHeaders.size());
            rptInfo.setExcelHeader(titleList);


            // 报表配置文件中name属性配置的值必须和Excel表头相同，为了防止用户修改name属性的值，在此再次验证name属性的值
            List<BaseRptColumn> rptCloumns = rptInfo.getRptColumns();
            for(BaseRptColumn rptColumn : rptCloumns) {
                String name = rptColumn.getName();
                if(!titleList.contains(name)) {
                    errroMsg = "xml文件中cloumn元素的name属性值【" + name + "】配置错误，该值无法和Excel表头对应";
                    throw new ServiceException(errroMsg);
                }
            }

            // 修改报表配置信息
            saveRptService.updateRptCfg(editHeader, rptInfo);

            // 保存文件
            String cfgFileName = "RPT_" + rptId + ".xml";
            File rptCfgFile = new File(rptConfigPath, cfgFileName);
            if (!rptCfgFile.exists()) {
                rptCfgFile.mkdirs();
            }
            rptCfg.transferTo(rptCfgFile);

            // 缓存报表配置数据
            System.out.println("缓存数据...");
            cacheManager.addRptCache(String.valueOf(rptId), rptInfo);

            jsonObject.put("status", "1");
        } catch (ServiceException e) {
            errroMsg = e.getMessage();
            jsonObject.put("status", "0");
            jsonObject.put("errorMsg", errroMsg);
        } catch (Exception e) {
            errroMsg = "修改报表失败";
            jsonObject.put("status", "0");
            jsonObject.put("errorMsg", errroMsg);
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 保存报表配置信息(仅修改报表名称或报表数据源信息)
     */
    @RequestMapping("/editRptInfo")
    @ResponseBody
    @PrivateHandlerMethod
    public JSONObject editRptCfg(HttpServletRequest request) {
        JSONObject jsonObject = new JSONObject();
        String errroMsg = "";
        try {
            // 根据报表ID查询报表信息
            String rptId = request.getParameter("rptId");  // 报表ID
            String rptName = request.getParameter("rptName");  // 报表名称
            String dbSource = request.getParameter("dbSource");  // 报表数据源
            String accessIn = request.getParameter("accessIn");  // 接入系统
            String editHeader = request.getParameter("editHeader");  // 是否修改表头
            String token = "";
            if(StringUtils.isNotBlank(accessIn)) {
                // 接入系统Token
                List<AccessIn> accessIns = rptMgrService.queryAccessInByCode(accessIn);
                if(!CollectionUtils.isEmpty(accessIns)) {
                    token = accessIns.get(0).getSysToken();
                }
            }

            BaseRpt baseRpt = (BaseRpt) cacheManager.getRptCache(rptId);

            // 不修改报表配置文件，仅修改报表名称或报表数据源
            baseRpt.setRptName(rptName);
            baseRpt.setDataSource(dbSource);
            baseRpt.setAccessSysCode(accessIn);
            baseRpt.setRptToken(token);
            saveRptService.updateRptCfg(editHeader, baseRpt);

            // 缓存报表配置数据
            System.out.println("缓存数据...");
            cacheManager.addRptCache(String.valueOf(rptId), baseRpt);

            jsonObject.put("status", "1");
        } catch (ServiceException e) {
            errroMsg = e.getMessage();
            jsonObject.put("status", "0");
            jsonObject.put("errorMsg", errroMsg);
        } catch (Exception e) {
            errroMsg = "修改报表失败";
            jsonObject.put("status", "0");
            jsonObject.put("errorMsg", errroMsg);
            e.printStackTrace();
        }
        return jsonObject;
    }
}
